﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.LanguageManagement.Dto;
using Volo.Abp.Localization;

namespace Volo.Abp.LanguageManagement
{
    [Authorize(LanguageManagementPermissions.LanguageTexts.Default)]
	public class LanguageTextAppService : LanguageAppServiceBase, IRemoteService, IApplicationService, ILanguageTextAppService
	{
		protected ILanguageTextRepository LanguageTextRepository { get; }

		protected IStringLocalizerFactory LocalizerFactory { get; }

		protected AbpLocalizationOptions _abpLocalizationOptions { get; }

		public LanguageTextAppService(ILanguageTextRepository languageTextRepository, IOptions<AbpLocalizationOptions> abpLocalizationOptions, IStringLocalizerFactory localizerFactory)
		{
			this.LanguageTextRepository = languageTextRepository;
			this.LocalizerFactory = localizerFactory;
			this._abpLocalizationOptions = abpLocalizationOptions.Value;
		}

		public virtual async Task<PagedResultDto<LanguageTextDto>> GetListAsync(GetLanguagesTextsInput input)
		{
			var list = new List<LanguageTextDto>();
			foreach (string resourceName in this.GetResourceNames(input))
			{
				list.AddRange(this.GetLocalizationsFromResource(input, resourceName));
			}

			var queryable = list.AsQueryable<LanguageTextDto>();
			bool flag = !input.Filter.IsNullOrWhiteSpace();
			queryable.WhereIf<LanguageTextDto>(flag, x =>
				 (x.Name != null && x.Name.IndexOf(input.Filter) >= 0) ||
				 (x.BaseValue != null && x.BaseValue.IndexOf(input.Filter) >= 0) ||
				 (!input.GetOnlyEmptyValues && x.Value != null && x.Value.IndexOf(input.Filter) >= 0)
			 );

			var result = queryable.OrderBy<LanguageTextDto>(input.Sorting ?? "Name ASC")
				.PageBy<LanguageTextDto>(input).ToList<LanguageTextDto>();

			return await Task.FromResult<PagedResultDto<LanguageTextDto>>(new PagedResultDto<LanguageTextDto>((long)queryable.Count<LanguageTextDto>(), result));
		}

		protected virtual List<string> GetResourceNames(GetLanguagesTextsInput input)
		{
			var list = new List<string>();
			if (input.ResourceName.IsNullOrWhiteSpace())
			{
				list.AddRange(from l in _abpLocalizationOptions.Resources.Values
							  select l.ResourceName);
			}
			else
			{
				list.Add(input.ResourceName);
			}
			return list;
		}

		public virtual Task<LanguageTextDto> GetAsync(string resourceName, string cultureName, string name, string baseCultureName)
		{
			var localizer = GetLocalizer(resourceName);
			var languageTextDto = new LanguageTextDto
			{
				Name = name,
				ResourceName = resourceName,
				CultureName = cultureName,
				BaseCultureName = baseCultureName
			};
			using (CultureHelper.Use(CultureInfo.GetCultureInfo(baseCultureName)))
			{
				string baseValue;
				if (baseCultureName == null)
				{
					baseValue = "";
				}
				else
				{
					var localizedString = localizer.GetAllStrings(false).FirstOrDefault(lt => lt.Name == name);
					if (localizedString != null)
					{
						if ((baseValue = localizedString.Value) != null)
						{
							languageTextDto.BaseValue = baseValue;
						}
					}
				}
			}
			using (CultureHelper.Use(CultureInfo.GetCultureInfo(cultureName)))
			{
				var localizedString = localizer.GetAllStrings(false).FirstOrDefault(lt => lt.Name == name);
				string value;
				if (localizedString != null)
				{
					if ((value = localizedString.Value) != null)
					{
						languageTextDto.Value = value;
					}
				}
			}
			return Task.FromResult<LanguageTextDto>(languageTextDto);
		}

		[Authorize(LanguageManagementPermissions.LanguageTexts.Edit)]
		public virtual async Task UpdateAsync(string resourceName, string cultureName, string name, string value)
		{
			if (value == null)
			{
				value = "";
			}
			using (CultureHelper.Use(CultureInfo.GetCultureInfo(cultureName)))
			{
				var localizedString = this.GetLocalizer(resourceName).GetAllStrings(false).FirstOrDefault((LocalizedString lt) => lt.Name == name);
				if ((((localizedString != null) ? localizedString.Value : null) ?? "") == value)
				{
					return;
				}
			}
			var languageText = (await this.LanguageTextRepository.GetListAsync()).FirstOrDefault(l => l.CultureName == cultureName && l.ResourceName == resourceName && l.Name == name);
			if (languageText == null)
			{
				var languageTextRepository = this.LanguageTextRepository;
				Guid guid = base.GuidGenerator.Create();
				string resourceName2 = resourceName;
				string cultureName2 = cultureName;
				string name2 = name;
				string text = value;
				var currentTenant = base.CurrentTenant;
				await languageTextRepository.InsertAsync(new LanguageText(guid, resourceName2, cultureName2, name2, text, (currentTenant != null) ? currentTenant.Id : null));
			}
			else
			{
				languageText.Value = value;
				await this.LanguageTextRepository.UpdateAsync(languageText);
			}
		}

		public virtual async Task RestoreToDefaultAsync(string resourceName, string cultureName, string name)
		{
			var languageText = (await this.LanguageTextRepository.GetListAsync()).FirstOrDefault(l => l.CultureName == cultureName && l.ResourceName == resourceName && l.Name == name);
			if (languageText != null)
			{
				await this.LanguageTextRepository.DeleteAsync(languageText);
			}
		}

		protected virtual List<LanguageTextDto> GetLocalizationsFromResource(GetLanguagesTextsInput input, string resourceName)
		{
			var localizer = this.GetLocalizer(resourceName);
			List<LocalizedString> list;
			using (CultureHelper.Use(CultureInfo.GetCultureInfo(input.BaseCultureName)))
			{
				list = localizer.GetAllStrings(true, false).ToList<LocalizedString>();
			}
			List<LocalizedString> source;
			using (CultureHelper.Use(CultureInfo.GetCultureInfo(input.TargetCultureName)))
			{
				source = localizer.GetAllStrings(false, false).ToList<LocalizedString>();
			}
			List<LanguageTextDto> list2 = new List<LanguageTextDto>();
			foreach (var baseLocalizedString in list)
			{
				var localizedString = source.FirstOrDefault((LocalizedString l) => l.Name == baseLocalizedString.Name);
				if (!input.GetOnlyEmptyValues || string.IsNullOrEmpty((localizedString != null) ? localizedString.Value : null))
				{
					var languageTextDto = new LanguageTextDto();
					languageTextDto.BaseCultureName = input.BaseCultureName;
					languageTextDto.CultureName = input.TargetCultureName;
					languageTextDto.Name = baseLocalizedString.Name;
					languageTextDto.BaseValue = baseLocalizedString.Value;
					languageTextDto.ResourceName = resourceName;
					if (localizedString == null || localizedString.Value == null)
					{
						languageTextDto.Value = "";
						list2.Add(languageTextDto);
					}
				}
			}
			return list2;
		}

		protected virtual IStringLocalizer GetLocalizer(LocalizationResource resource)
		{
			return this.LocalizerFactory.Create(resource.ResourceType);
		}

		protected virtual IStringLocalizer GetLocalizer(string recourseName)
		{
			return this.GetLocalizer(this.GetLocalizationResource(recourseName));
		}

		protected virtual LocalizationResource GetLocalizationResource(string resourceName)
		{
			var localizationResource = this._abpLocalizationOptions.Resources.Values.FirstOrDefault(r => r.ResourceName == resourceName);
			if (localizationResource == null)
			{
				throw new AbpException("Resource not found: " + resourceName);
			}
			return localizationResource;
		}
	}
}
